<?php
namespace app\weixin\controller;
use wechat\Wechat;
use think\Session;
use think\db\Expression;
use think\Controller;
/**
 *  @file : BaseController.php
 *  @brief: 
 */
class BaseController extends Controller {

  protected $wapi = null;// wechat\Wechat
  protected $conf = [];  // 当前模块的公众号配置

  protected $user = null; // 关注用户
  protected $auid = 0;    // 代理用户UserID

  protected $beforeActionList = [
    'checkWxAuth' => [  // 特殊Action不需要微信先授权
      'except' => 'authorize',
    ],
    'checkHtAuth' => [  // 特殊Action不需要后台先登录
      'except' => 'authorize'
    ],
  ];

  protected $AGameID = 0; // 推广员邀请码
  protected $Channel = 0; // 渠道号
  protected $KindID = 0;  // 小游戏
  
  // 后台分页查询相关
  protected $pageSize    = 10;
  protected $pageCurrent = 1;
  protected $pageMaxSize = 30;
  protected $orderField  = '';
  protected $orderDirection = 'DESC';

  /**
   *  @brief  : 初始化, 适配三级域名
   *  @return : none
   *  @details: http://gg.ag.game654.com/download/index.html?state=AGENT442196KINDID0
   */
  protected function _initialize() {
    $ref = $this->request->url(true); // 当前请求完整URL, 包括QUERY_STRING
    /////// 渠道号适配, 处理一个公众号对应多个channel ////////////////////////////////////
    $mode = $this->request->param('mode/s', '', 'trim');
    if ($mode == 'normal') {
      unset($this->beforeActionList['checkWxAuth']);
    }
    $state = $this->request->param('state/s', '', 'trim');
    if (!empty($state)) { // 明确指定`AGameID-KindID-Channel`
      $state = preg_replace('/[a-zA-Z]+/', ',', $state);
      $state = trim($state, ',');
      $state = explode(',', $state);
      $this->AGameID = empty($state[0]) ? 0 : $state[0] * 1;
      $this->KindID  = empty($state[1]) ? 0 : $state[1] * 1;
      $this->Channel = empty($state[2]) ? 0 : $state[2] * 1;
      if ($this->Channel > 0) {
        Session::set('WXOAUTH.CHANNEL', $this->Channel);
      }
    }

    // 默认 或者 未明确指定`AGameID-KindID-Channel`
    $this->Channel = Session::get('WXOAUTH.CHANNEL');
    if ($this->Channel <= 0) {
      $this->Channel = config('DEFAULT_CHANNEL'); // 公众号默认Channel
    }
    $share = config("share.{$this->Channel}");
    $this->conf = config("wxgzh.{$share['gzh_key']}");
    $this->wapi = new Wechat($this->conf);
  }
  /**
   *  @brief  : 检测后台是否已登录
   *  @return : none|redirect
   *  @details: 如果已经登录则继续向下执行到控制器Action, 否则重定向到登录页面
   */
  protected function checkHtAuth() {
    $auid = Session::get('HTOAUTH.AUID');
    if ($auid <= 0) { // 没有登陆
      $ref = $this->request->url(true); // 当前请求完整URL, 包括QUERY_STRING
      $ref = urlencode($ref);
      $url = url('index/login', '', true, true);// 后台登陆网关
      $url = "{$url}?ref={$ref}";
      return $this->redirect($url);
    }
    $this->auid = $auid;
    $this->_initPageVars();
  }
  /**
   *  @brief  : 检测微信是否已授权
   *  @return : none|redirect
   *  @details: 如果已经授权则继续向下执行到控制器Action, 否则重定向到授权
   */
  protected function checkWxAuth() {
    do {
      $eax = Session::has('WXOAUTH.USER');
      if ($eax) { // 有缓存授权用户信息
        $OPENID       = Session::get('WXOAUTH.OPENID');
        $ACCESS_TOKEN = Session::get('WXOAUTH.ACCESS_TOKEN');
        $EXPIRES_IN   = Session::get('WXOAUTH.EXPIRES_IN');
        $eax = $EXPIRES_IN > time() ? true : false;
        // $eax = $this->wapi->getOauthAuth($ACCESS_TOKEN, $OPENID); // 检验`授权凭证`(access_token)是否有效
        if (!$eax) { // `授权凭证`过期|调用失败, 刷新access_token
          $REFRESH_TOKEN = Session::get('WXOAUTH.REFRESH_TOKEN');
          $token = $this->wapi->getOauthRefreshToken($REFRESH_TOKEN);
          if (!empty($token)) {
            $eax = $this->_UpdateWxOauth($token);
          }
        }
        if ($eax) {
          $this->user = Session::get('WXOAUTH.USER');
          break;
        }
      }
      // 没有缓存授权用户信息|刷新access_token失败
      Session::delete('WXOAUTH');
      $ref = $this->request->url(true); // 当前请求完整URL, 包括QUERY_STRING
      $ref = urlencode($ref);
      $url = url('base/authorize', '', true, true);
      $url = "{$url}?ref={$ref}";
      $state= $this->request->param('state/s', '');
      $eax = $this->wapi->getOauthRedirect($url, $state, Wechat::SNSAPI_USERINFO);
      return $this->redirect($eax);
    } while (false);
  }
  /**
   *  @brief  : 微信公众号网页授权回调
   *  @return : redirect|JSON
   *  @details:
   */
  public function authorizeAction() {
    $state= $this->request->param('state/s', '');
    $ref  = $this->request->param('ref/s', '');
    //////////////////////////////////////////////////////////////
    $token = $this->wapi->getOauthAccessToken(); // 通过code换取网页授权access_token
    if (empty($token) || !($token && $this->_UpdateWxOauth($token))) {
      Session::delete ('WXOAUTH');
      trace(['token'=>$token, 'errno' => $this->wapi->errCode, 'error' => $this->wapi->errMsg]);
      return abort(500, '授权失败!');
    }
    trace($this->user);
    //////////////////////////////
    if ($this->AGameID > 0) { // `state`有带邀请码, 绑定推广员与玩家账号
      AgentBind($this->user['UserID'], $this->AGameID, $this->KindID);
    }
    ////////// 处理返回 //////////
    if (!empty($ref)) {
      if (stripos($ref, '/share/authorize') !== false) {
        $ref = $ref.'&code='.$this->user['unionid']; // 分享-在线体验追加unionid
      }
      return $this->redirect($ref);
    } else {
      return abort(200, '授权成功!');
    }
  }
  /**
   *  创建/更新/数据库/SESSION/及相关成员变量
   */
  private function _UpdateWxOauth($token) {
    $user = $this->wapi->getOauthUserinfo($token['access_token'], $token['openid']); // 拉取用户信息(需scope为snsapi_userinfo)
    if (empty($user) || empty($user['unionid'])) {  // 强制`unionid`判断
      Session::delete ('WXOAUTH');
      return false;
    }
    // 创建/更新/用户账号, 不管是否是推广员, 全都创建
    $eax = CPP_EfficacyOtherPlatform(
      4,
      $user['unionid'], // 用户Uin
      $user['openid'],  // 用户OpenID
      $user['nickname'], // 用户昵称
      $user['sex'], // 用户性别 0=未知; 1=男性; 2=女性;
      request()->ip(), // 连接地址
      md5($user['unionid']), // 机器标识
      $user['headimgurl'], // 微信头像地址
      $this->Channel
    );
    $user['UserID'] = $eax['UserID'] ?? 0;
    $this->user = $user;
    Session::set('WXOAUTH.USER', $user);
    Session::set('WXOAUTH.OPENID', $token['openid']);
    Session::set('WXOAUTH.ACCESS_TOKEN', $token['access_token']);
    Session::set('WXOAUTH.REFRESH_TOKEN', $token['refresh_token']);
    Session::set('WXOAUTH.EXPIRES_IN', time() + 1 * 60 * 60);
    return true;
  }
  /**
   * 过滤/初始化分页查询所必须变量
   */
  private function _initPageVars() {
    $C = [
      'orderField'      => 'order',
      'orderDirection'  => 'by',
      'pageSize'        => 'size',
      'pageCurrent'     => 'page',
    ];
    // 排序变量
    $this->orderField     = $this->request->param("{$C['orderField']}/s", '', 'trim,strtoupper');
    $this->orderDirection = $this->request->param("{$C['orderDirection']}/s", 'DESC', 'trim,strtoupper');
    $this->orderDirection = in_array($this->orderDirection, ['DESC', 'ASC']) ? $this->orderDirection : 'DESC';
    // 分页变量
    $pageSize     = $this->request->param("{$C['pageSize']}/d", 0);
    $pageCurrent  = $this->request->param("{$C['pageCurrent']}/d", 0);
    $this->pageSize   = ($pageSize > 0 && $pageSize <= $this->pageMaxSize) ? $pageSize : $this->pageSize;
    $this->pageCurrent= $pageCurrent>0 ? $pageCurrent : $this->pageCurrent;
  }
  /**
   * 重载父类fetch方法
   */
  protected function fetch($template = '', $vars = [], $replace = [], $config = []) {
    $vars = array_merge($vars, [  // 分页查询所必须变量赋值
      'PageSize'        => $this->pageSize,
      'PageCurrent'     => $this->pageCurrent,
      'OrderField'      => $this->orderField,
      'OrderDirection'  => $this->orderDirection,
      'Channel'  => $this->Channel,
    ]);
    return $this->view->fetch($template, $vars, $replace, $config);
  }
}
